package com.code.translate.plugins;

import com.code.translate.enums.Constants;
import com.code.translate.function.TextTranslatePlugin;
import com.code.translate.utils.*;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;

import javax.servlet.http.Cookie;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author ggh
 * @date 2022/7/17
 * <p>
 * 百度翻译
 */
public class BaiduTranslatePlugin extends TextTranslatePlugin {
    private final static String indexUrl = "https://fanyi.baidu.com/";
    private final static String translateUrl = "https://fanyi.baidu.com/v2transapi?from=en&to=zh";
    private final static String refer = "https://fanyi.baidu.com/";

    private final static Integer signleTranslateTextLen = 5000;

    private static BaiduTranslatePlugin singleton = new BaiduTranslatePlugin();

    private BaiduTranslatePlugin() {
    }

    public static BaiduTranslatePlugin getSingleton() {
        return singleton;
    }

    @Override
    protected Map<String, Object> prepare() throws IOException {
        // 第一次访问没有cookie，需要刷新两遍
        RequestEntity requestEntity = RequestEntity.get(URI.create(indexUrl)).build();
        ResponseEntity responseEntity = HttpUtils.reqEntity(requestEntity, false);

        Map<String, Cookie> cookieMap = CookieUtils.parseResponseCookie(responseEntity.getHeaders().get("set-cookie"));
        String cookie = CookieUtils.buildCookie(cookieMap.get("BAIDUID_BFESS"), cookieMap.get("BAIDUID"));

        // 第二次访问,解析token和gtk
        Map<String, String> headers = new HashMap<>(1);
        headers.put("Cookie", cookie);
        String result = HttpUtils.req(indexUrl, HttpMethod.GET, headers, null);
        result = result.substring(result.length() - 20000);
        String token = PatternUtils.regex(result, "token\\:\\s?\\'([A-Za-z0-9]{32})\\'\\,");
        String gtk = PatternUtils.regex(result, "gtk\\s?=\\s?\\\"([0-9\\.]{10,20})\\\"");

        Map<String, Object> params = new HashMap<>(3);
        params.put("token", token);
        params.put("gtk", gtk);
        params.put("cookie", cookie);
        return params;
    }

    @Override
    protected String doTranslate(String text, Map<String, Object> preParams) throws IOException {
        Map<String, String> headers = new HashMap<>(1);
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        headers.put("Referer", refer);
        headers.put("Cookie", preParams.get("cookie").toString());
        Map<String, Object> params = structCommonParams(preParams, text);


        if (text.length() > signleTranslateTextLen) {
            List<String> singleTextList = StringUtils.splitString(text, signleTranslateTextLen, Constants.SEGEMENT);

            StringBuffer buffer = new StringBuffer();

            for (String singleText : singleTextList) {
                Object jsResult = JSUtils.execute("js/baidu-java.js", "tl", singleText);
                if (jsResult != null) {
                    params.put("sign", jsResult.toString());
                }
                params.put("query", singleText);

                String result = HttpUtils.req(translateUrl, HttpMethod.POST, headers, params);

                if (!StringUtils.isEmpty(result) && result.contains("status\":0,")) {
                    buffer.append(JsonpathUtils.read(result, "$.trans_result.data[*].dst"));
                }
            }
            return buffer.toString();
        } else {
            Object jsResult = JSUtils.execute("js/baidu-java.js", "tl", text);
            if (jsResult != null) {
                params.put("sign", jsResult.toString());
            }
            params.put("query", text);
            String result = HttpUtils.req(translateUrl, HttpMethod.POST, headers, params);

            if (!StringUtils.isEmpty(result) && result.contains("status\":0,")) {
                return JsonpathUtils.read(result, "$.trans_result.data[*].dst");
            }
        }

        return null;
    }

    private static Map<String, Object> structCommonParams(Map<String, Object> preParams, String text) {
        Map<String, Object> params = new HashMap<>(3);
        params.put("from", "en");
        params.put("to", "zh");
        params.put("simple_means_flag", 3);
        params.put("transtype", "translang");
        params.put("domain", "common");
        params.put("token", preParams.get("token"));

        return params;
    }
}
